package com.wenx.v3system.modular.cloud.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenx.v3core.error.BusinessException;
import com.wenx.v3system.modular.cloud.domain.dto.SysUserDto;
import com.wenx.v3system.modular.cloud.domain.dto.UserAssignmentDataDto;
import com.wenx.v3system.modular.cloud.domain.dto.SysRoleDto;
import com.wenx.v3system.modular.cloud.domain.dto.SysDepartmentDto;
import com.wenx.v3system.modular.cloud.domain.dto.SysTeamDto;
import com.wenx.v3system.modular.cloud.domain.maps.SysUserMap;
import com.wenx.v3system.modular.cloud.domain.maps.SysRoleMap;
import com.wenx.v3system.modular.cloud.domain.maps.SysDepartmentMap;
import com.wenx.v3system.modular.cloud.domain.maps.SysTeamMap;
import com.wenx.v3system.modular.cloud.domain.po.SysUser;
import com.wenx.v3system.modular.cloud.domain.po.SysRole;
import com.wenx.v3system.modular.cloud.domain.po.SysDepartment;
import com.wenx.v3system.modular.cloud.domain.po.SysTeam;
import com.wenx.v3system.modular.cloud.domain.po.SysUserRole;
import com.wenx.v3system.modular.cloud.domain.po.SysDepartmentUser;
import com.wenx.v3system.modular.cloud.domain.po.SysUserTeam;
import com.wenx.v3system.modular.cloud.domain.query.SysUserQuery;
import com.wenx.v3system.modular.cloud.mapper.SysUserMapper;
import com.wenx.v3system.modular.cloud.mapper.SysRoleMapper;
import com.wenx.v3system.modular.cloud.mapper.SysDepartmentMapper;
import com.wenx.v3system.modular.cloud.mapper.SysTeamMapper;
import com.wenx.v3system.modular.cloud.mapper.SysUserRoleMapper;
import com.wenx.v3system.modular.cloud.mapper.SysDepartmentUserMapper;
import com.wenx.v3system.modular.cloud.mapper.SysUserTeamMapper;
import com.wenx.v3system.modular.cloud.service.SysUserPermissionService;
import com.wenx.v3system.modular.cloud.service.SysUserRestService;
import com.wenx.anno.DataPermission;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 系统用户服务实现类
 * 基于Enhanced RBAC权限模型重构
 * 使用v3-system数据源
 *
 * @author wenx
 */
@Service
public class SysUserRestServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserRestService {

    private static final Logger log = LoggerFactory.getLogger(SysUserRestServiceImpl.class);
    
    private final PasswordEncoder passwordEncoder;
    private final SysUserPermissionService userPermissionService;
    private final SysRoleMapper sysRoleMapper;
    private final SysDepartmentMapper sysDepartmentMapper;
    private final SysTeamMapper sysTeamMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysDepartmentUserMapper sysDepartmentUserMapper;
    private final SysUserTeamMapper sysUserTeamMapper;
    private final SysRoleMap sysRoleMap;
    private final SysDepartmentMap sysDepartmentMap;
    private final SysTeamMap sysTeamMap;

    public SysUserRestServiceImpl(PasswordEncoder passwordEncoder,
                                  SysUserPermissionService userPermissionService,
                                  SysRoleMapper sysRoleMapper,
                                  SysDepartmentMapper sysDepartmentMapper,
                                  SysTeamMapper sysTeamMapper,
                                  SysUserRoleMapper sysUserRoleMapper,
                                  SysDepartmentUserMapper sysDepartmentUserMapper,
                                  SysUserTeamMapper sysUserTeamMapper,
                                  SysRoleMap sysRoleMap,
                                  SysDepartmentMap sysDepartmentMap,
                                  SysTeamMap sysTeamMap) {
        this.passwordEncoder = passwordEncoder;
        this.userPermissionService = userPermissionService;
        this.sysRoleMapper = sysRoleMapper;
        this.sysDepartmentMapper = sysDepartmentMapper;
        this.sysTeamMapper = sysTeamMapper;
        this.sysUserRoleMapper = sysUserRoleMapper;
        this.sysDepartmentUserMapper = sysDepartmentUserMapper;
        this.sysUserTeamMapper = sysUserTeamMapper;
        this.sysRoleMap = sysRoleMap;
        this.sysDepartmentMap = sysDepartmentMap;
        this.sysTeamMap = sysTeamMap;
    }

    @Override
    @DataPermission(tables = {"sys_user"}, type = DataPermission.PermissionType.DEPT_SCOPE, description = "部门管理员只能查看本部门用户")
    public IPage<?> page(SysUserQuery query) {
        // 处理空值情况，避免空指针异常
        if (query == null) {
            query = new SysUserQuery();
        }

        SysUserQuery finalQuery = query;
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
                // 基础字段模糊查询
                .like(StringUtils.hasText(query.getUsername()), SysUser::getUsername, query.getUsername())
                .like(StringUtils.hasText(query.getRealName()), SysUser::getRealName, query.getRealName())
                .like(StringUtils.hasText(query.getEmail()), SysUser::getEmail, query.getEmail())
                .like(StringUtils.hasText(query.getPhone()), SysUser::getPhone, query.getPhone())
                // 精确查询条件
                .eq(query.getStatus() != null, SysUser::getStatus, query.getStatus())
                .eq(query.getGender() != null, SysUser::getGender, query.getGender())
                // 关键词搜索（支持多字段模糊查询）
                .and(StringUtils.hasText(query.getKeyword()), w -> w
                        .like(SysUser::getUsername, finalQuery.getKeyword())
                        .or().like(SysUser::getRealName, finalQuery.getKeyword())
                        .or().like(SysUser::getEmail, finalQuery.getKeyword())
                )
                .orderByDesc(SysUser::getCreateTime);
        
        IPage<SysUser> result = super.page(new Page<>(query.getCurrent(), query.getSize()), wrapper);
        // 转换为DTO并填充关联数据
        return result.convert(this::convertToDtoWithRelations);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysUserDto dto) {
        // 参数校验
        if (!StringUtils.hasText(dto.getUsername())) {
            throw new BusinessException("用户名不能为空");
        }
        if (!StringUtils.hasText(dto.getPassword())) {
            throw new BusinessException("密码不能为空");
        }
        
        // 检查用户名是否已存在
        if (checkUsernameExists(dto.getUsername(), null)) {
            throw new BusinessException("用户名已存在");
        }
        
        // 检查邮箱是否已存在
        if (StringUtils.hasText(dto.getEmail()) && checkEmailExists(dto.getEmail(), null)) {
            throw new BusinessException("邮箱已存在");
        }
        
        SysUser user = SysUserMap.INSTANCE.toPo(dto);
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        
        if (!super.save(user)) {
            throw new BusinessException("创建用户失败");
        }
        
        // 保存用户关联关系
        saveUserRelations(user.getId(), dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Serializable id) {
        SysUser user = super.getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 检查是否为超级管理员（基于查询到的user对象判断）
        if (isSuperAdminUser(user)) {
            throw new BusinessException("不能删除超级管理员");
        }
        
        if (!super.removeById(id)) {
            throw new BusinessException("删除用户失败");
        }
        
        // 清除用户权限缓存
        clearUserPermissionCache(Long.valueOf(id.toString()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUserDto dto) {
        SysUser existingUser = super.getById(dto.getId());
        if (existingUser == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 检查用户名是否已存在（排除自己）
        if (StringUtils.hasText(dto.getUsername()) && checkUsernameExists(dto.getUsername(), dto.getId())) {
            throw new BusinessException("用户名已存在");
        }
        
        // 检查邮箱是否已存在（排除自己）
        if (StringUtils.hasText(dto.getEmail()) && checkEmailExists(dto.getEmail(), dto.getId())) {
            throw new BusinessException("邮箱已存在");
        }
        
        SysUser user = SysUserMap.INSTANCE.toPo(dto);
        
        // 如果有新密码，进行加密
        if (StringUtils.hasText(dto.getPassword())) {
            user.setPassword(passwordEncoder.encode(dto.getPassword()));
        } else {
            user.setPassword(existingUser.getPassword());
        }
        
        if (!super.updateById(user)) {
            throw new BusinessException("更新用户失败");
        }
        
        // 更新用户关联关系
        updateUserRelations(dto.getId(), dto);
        
        // 清除用户权限缓存
        clearUserPermissionCache(dto.getId());
    }

    @Override
    public Object get(Serializable id) {
        SysUser user = super.getById(id);
        return user != null ? convertToDto(user) : null;
    }

    @Override
    public SysUserDto getUserByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, username);
        SysUser user = super.getOne(wrapper);
        return user != null ? convertToDto(user) : null;
    }

    @Override
    public SysUserDto login(String username, String password) {
        SysUserDto user = getUserByUsername(username);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new BusinessException("密码错误");
        }
        
        if (user.getStatus() != 1) {
            throw new BusinessException("用户已被禁用");
        }
        
        // 更新最后登录时间
        updateLastLoginInfo(user.getId(), null);
        
        return user;
    }


    @Override
    @Cacheable(value = "system:user:permissions", key = "#userId")
    public List<String> getUserPermissions(Long userId) {
        Set<String> permissions = userPermissionService.getUserPermissions(userId);
        return new ArrayList<>(permissions);
    }

    @Override
    public boolean hasPermission(Long userId, String permission) {
        return userPermissionService.hasPermission(userId, permission);
    }

    @Override
    public List<Long> getUserAccessibleMenus(Long userId) {
        Set<Long> menus = userPermissionService.getUserMenus(userId);
        return new ArrayList<>(menus);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String resetUserPassword(Long userId) {
        SysUser user = super.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        String newPassword = generateRandomPassword();
        user.setPassword(passwordEncoder.encode(newPassword));
        
        if (!super.updateById(user)) {
            throw new BusinessException("重置密码失败");
        }
        
        return newPassword;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserStatus(Long userId, Integer status) {
        SysUser user = super.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        user.setStatus(status);
        
        if (!super.updateById(user)) {
            throw new BusinessException("更新用户状态失败");
        }
        
        clearUserPermissionCache(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLastLoginInfo(Long userId, String loginIp) {
        SysUser user = super.getById(userId);
        if (user != null) {
            // 注意：SysUser实体没有lastLoginTime和lastLoginIp字段
            // 如需记录登录信息，可考虑使用单独的登录日志表
            super.updateById(user);
        }
    }

    @Override
    public boolean checkUsernameExists(String username, Long excludeId) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, username);
        
        if (excludeId != null) {
            wrapper.ne(SysUser::getId, excludeId);
        }
        
        return super.count(wrapper) > 0;
    }

    @Override
    public boolean checkEmailExists(String email, Long excludeId) {
        if (!StringUtils.hasText(email)) {
            return false;
        }
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getEmail, email);
        
        if (excludeId != null) {
            wrapper.ne(SysUser::getId, excludeId);
        }
        
        return super.count(wrapper) > 0;
    }

    /**
     * 转换用户实体为DTO并填充关联数据
     */
    private SysUserDto convertToDtoWithRelations(SysUser user) {
        SysUserDto dto = SysUserMap.INSTANCE.toDto(user);
        
        // 查询用户角色
        List<SysUserRole> userRoles = sysUserRoleMapper.selectList(
                new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, user.getId())
        );
        if (!userRoles.isEmpty()) {
            List<Long> roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
            List<SysRole> roles = sysRoleMapper.selectBatchIds(roleIds);
            dto.setRoles(roles.stream().map(sysRoleMap::toDto).collect(Collectors.toList()));
        }
        
        // 查询用户部门
        List<SysDepartmentUser> departmentUsers = sysDepartmentUserMapper.selectList(
                new LambdaQueryWrapper<SysDepartmentUser>().eq(SysDepartmentUser::getUserId, user.getId())
        );
        if (!departmentUsers.isEmpty()) {
            List<Long> departmentIds = departmentUsers.stream().map(SysDepartmentUser::getDepartmentId).collect(Collectors.toList());
            List<SysDepartment> departments = sysDepartmentMapper.selectBatchIds(departmentIds);
            dto.setDepartments(departments.stream().map(sysDepartmentMap::toDto).collect(Collectors.toList()));
        }
        
        // 查询用户团队
        List<SysUserTeam> userTeams = sysUserTeamMapper.selectList(
                new LambdaQueryWrapper<SysUserTeam>().eq(SysUserTeam::getUserId, user.getId())
        );
        if (!userTeams.isEmpty()) {
            List<Long> teamIds = userTeams.stream().map(SysUserTeam::getTeamId).collect(Collectors.toList());
            List<SysTeam> teams = sysTeamMapper.selectBatchIds(teamIds);
            dto.setTeams(teams.stream().map(sysTeamMap::toDto).collect(Collectors.toList()));
        }
        
        return dto;
    }

    private SysUserDto convertToDto(SysUser user) {
        if (user == null) {
            return null;
        }
        // 使用MapStruct映射器进行转换，符合代码架构风格
        return SysUserMap.INSTANCE.toDto(user);
    }

    /**
     * 判断用户是否为超级管理员
     * 基于查询到的user对象进行判断，避免额外的数据库查询
     * 
     * @param user 用户实体对象
     * @return true-是超级管理员，false-不是
     */
    private boolean isSuperAdminUser(SysUser user) {
        if (user == null) {
            return false;
        }
        
        // 方式1：根据用户名判断（常用方式）
        if ("admin".equals(user.getUsername()) || "superadmin".equals(user.getUsername())) {
            return true;
        }
        
        // 方式2：根据用户ID判断（初始超级管理员ID通常为1）
        if (user.getId() != null && user.getId().equals(1L)) {
            return true;
        }
        
        return false;
    }

    /**
     * 生成随机密码
     * 
     * @return 随机密码字符串
     */
    private String generateRandomPassword() {
        return UUID.randomUUID().toString().substring(0, 8);
    }

    @Override
    @CacheEvict(value = {"system:user:roles", "system:user:permissions"}, key = "#userId")
    public void clearUserPermissionCache(Long userId) {
        log.debug("清除用户权限缓存，用户ID: {}", userId);
        userPermissionService.clearUserPermissionCache(userId);
    }

    @Override
    @CacheEvict(value = {"system:user:roles", "system:user:permissions"}, allEntries = true)
    public void clearAllPermissionCache() {
        log.debug("清除所有用户权限缓存");
        userPermissionService.clearAllPermissionCache();
    }

    @Override
    @DataPermission(tables = {"sys_user"}, type = DataPermission.PermissionType.DEPT_SCOPE, description = "根据部门ID获取用户列表")
    public List<SysUserDto> getUsersByDepartmentId(Long departmentId) {
        if (departmentId == null) {
            throw new BusinessException("部门ID不能为空");
        }
        
        // 查询部门用户关联
        List<SysDepartmentUser> departmentUsers = sysDepartmentUserMapper.selectList(
                new LambdaQueryWrapper<SysDepartmentUser>().eq(SysDepartmentUser::getDepartmentId, departmentId)
        );
        
        if (departmentUsers.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 获取用户ID列表
        List<Long> userIds = departmentUsers.stream().map(SysDepartmentUser::getUserId).collect(Collectors.toList());
        
        // 查询用户信息
        List<SysUser> users = super.listByIds(userIds);
        return users.stream().map(this::convertToDtoWithRelations).collect(Collectors.toList());
    }

    @Override
    public UserAssignmentDataDto getUserAssignmentData() {
        UserAssignmentDataDto result = new UserAssignmentDataDto();
        
        // 获取所有启用的角色
        LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysRole::getDeleted, false)
                   .eq(SysRole::getStatus, 1)
                   .orderByAsc(SysRole::getSort)
                   .orderByDesc(SysRole::getCreateTime);
        List<SysRole> roles = sysRoleMapper.selectList(roleWrapper);
        result.setRoles(roles.stream().map(sysRoleMap::toDto).collect(Collectors.toList()));
        
        // 获取所有启用的部门
        LambdaQueryWrapper<SysDepartment> deptWrapper = new LambdaQueryWrapper<>();
        deptWrapper.eq(SysDepartment::getDeleted, false)
                   .eq(SysDepartment::getStatus, 1)
                   .orderByAsc(SysDepartment::getSort)
                   .orderByDesc(SysDepartment::getCreateTime);
        List<SysDepartment> departments = sysDepartmentMapper.selectList(deptWrapper);
        result.setDepartments(departments.stream().map(sysDepartmentMap::toDto).collect(Collectors.toList()));
        
        // 获取所有启用的团队
        LambdaQueryWrapper<SysTeam> teamWrapper = new LambdaQueryWrapper<>();
        teamWrapper.eq(SysTeam::getDeleted, false)
                   .eq(SysTeam::getStatus, 1)
                   .orderByAsc(SysTeam::getSort)
                   .orderByDesc(SysTeam::getCreateTime);
        List<SysTeam> teams = sysTeamMapper.selectList(teamWrapper);
        result.setTeams(teams.stream().map(sysTeamMap::toDto).collect(Collectors.toList()));
        
        return result;
    }

    /**
     * 保存用户关联关系（角色、部门、团队）
     * 支持处理前端发送的简化数据格式
     */
    private void saveUserRelations(Long userId, SysUserDto dto) {
        // 保存用户角色关联
        if (dto.getRoles() != null && !dto.getRoles().isEmpty()) {
            for (SysRoleDto role : dto.getRoles()) {
                SysUserRole userRole = new SysUserRole();
                userRole.setUserId(userId);
                userRole.setRoleId(role.getId());
                sysUserRoleMapper.insert(userRole);
            }
        } else if (dto.getSimpleRoles() != null && !dto.getSimpleRoles().isEmpty()) {
            // 处理前端发送的简化角色数据格式
            for (SysUserDto.SimpleReference ref : dto.getSimpleRoles()) {
                try {
                    SysUserRole userRole = new SysUserRole();
                    userRole.setUserId(userId);
                    userRole.setRoleId(Long.valueOf(ref.getId()));
                    sysUserRoleMapper.insert(userRole);
                } catch (NumberFormatException e) {
                    log.warn("无效的角色ID格式: {}", ref.getId());
                }
            }
        }
        
        // 保存用户部门关联
        if (dto.getDepartments() != null && !dto.getDepartments().isEmpty()) {
            for (SysDepartmentDto dept : dto.getDepartments()) {
                SysDepartmentUser departmentUser = new SysDepartmentUser();
                departmentUser.setUserId(userId);
                departmentUser.setDepartmentId(dept.getId());
                sysDepartmentUserMapper.insert(departmentUser);
            }
        } else if (dto.getSimpleDepartments() != null && !dto.getSimpleDepartments().isEmpty()) {
            // 处理前端发送的简化部门数据格式
            for (SysUserDto.SimpleReference ref : dto.getSimpleDepartments()) {
                try {
                    SysDepartmentUser departmentUser = new SysDepartmentUser();
                    departmentUser.setUserId(userId);
                    departmentUser.setDepartmentId(Long.valueOf(ref.getId()));
                    sysDepartmentUserMapper.insert(departmentUser);
                } catch (NumberFormatException e) {
                    log.warn("无效的部门ID格式: {}", ref.getId());
                }
            }
        }
        
        // 保存用户团队关联
        if (dto.getTeams() != null && !dto.getTeams().isEmpty()) {
            for (SysTeamDto team : dto.getTeams()) {
                SysUserTeam userTeam = new SysUserTeam();
                userTeam.setUserId(userId);
                userTeam.setTeamId(team.getId());
                sysUserTeamMapper.insert(userTeam);
            }
        } else if (dto.getSimpleTeams() != null && !dto.getSimpleTeams().isEmpty()) {
            // 处理前端发送的简化团队数据格式
            for (SysUserDto.SimpleReference ref : dto.getSimpleTeams()) {
                try {
                    SysUserTeam userTeam = new SysUserTeam();
                    userTeam.setUserId(userId);
                    userTeam.setTeamId(Long.valueOf(ref.getId()));
                    sysUserTeamMapper.insert(userTeam);
                } catch (NumberFormatException e) {
                    log.warn("无效的团队ID格式: {}", ref.getId());
                }
            }
        }
    }

    /**
     * 更新用户关联关系（角色、部门、团队）
     * 使用物理删除避免唯一约束冲突
     */
    private void updateUserRelations(Long userId, SysUserDto dto) {
        // 使用自定义物理删除方法，避免唯一约束冲突
        int userRoleDeleted = sysUserRoleMapper.physicalDeleteByUserId(userId);
        log.info("物理删除用户角色关联，用户ID: {}, 删除记录数: {}", userId, userRoleDeleted);
        
        int deptUserDeleted = sysDepartmentUserMapper.physicalDeleteByUserId(userId);
        log.info("物理删除用户部门关联，用户ID: {}, 删除记录数: {}", userId, deptUserDeleted);
        
        int userTeamDeleted = sysUserTeamMapper.physicalDeleteByUserId(userId);
        log.info("物理删除用户团队关联，用户ID: {}, 删除记录数: {}", userId, userTeamDeleted);
        
        // 重新保存关联关系
        saveUserRelations(userId, dto);
    }
}
